<?php
/**
*
* 功能描述（服务器入口）
*
* @author suoya <jlusuoya@gmail.com>
* @version 1
*/
error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');
session_start();
$frame = array(
	1 => "web",
	2 => "adm",
	3 => "oas",
);

define('SRV_BASE', "../" . $frame[$branch] . "_server/");
define('CTRL_DIR', SRV_BASE . "controller/");
define('MODEL_DIR', SRV_BASE . "model/");
require_once("include/log.php");
require_once("include/configue.php");
require_once("include/constant.php");
require_once("include/lang.php");
require_once("include/PdoHelper.php");
require_once(CTRL_DIR . "base.con.php");
require_once(MODEL_DIR . "base.mod.php");
if(array_key_exists('cookie', $web_root))
	setcookie('PHPSESSID', session_id(), 0, '/', $web_root['cookie']);
if(array_key_exists('__ajax', $_GET))
	$ajax = true;
else
	$ajax = false;
function run()
{
	if(RAND_TEST)
		RandParam();
	if(DEBUG && CHECK_CONF && !CheckWeb()) //配置未通过检测，禁止执行，报错由函数内输出
		return true;
	$ctrlbase = "index";
	$method = "index";
	if(array_key_exists("action", $_GET))
	{
		$arr = explode(".", $_GET["action"]);
		if(!empty($arr[0]) && !empty($arr[1]))
		{
			$ctrlbase = strtolower($arr[0]);
			$method = strtolower($arr[1]);
			if(strncmp($method, "self", 4) == 0)
				request_error(1, "method is forbidden");
		}
		else
			request_error(1, "action is not right");
	}
	$file = CTRL_DIR . $ctrlbase . ".con.php";
	if(!file_exists($file))
		request_error(1, "$file is not exist");
	include($file);
	$ctrl = "Ctrl" . $ctrlbase;
	$obj = new $ctrl();
	if(!method_exists($obj, $method))
		request_error(1, "$ctrl.$method is not exist");

	$perm = new ReflectionMethod($ctrl, $method);
	$pval = Reflection::getModifierNames($perm->getModifiers());
	if($pval[0] != "public")
		request_error(1, "$ctrl.$method is not public:" . $pval[0]);
	$obj->CheckPermissions($method);

	if(array_key_exists($method, $obj->paramCheck))
	{
		$chret = check_param($obj, $method);
		if($chret == "0")
			$ret = $obj->$method();
		else
			$ret = RT_EPARAM;
	}
	else
		$ret = $obj->$method();
	switch($ret)
	{
	case RT_EPARAM: request_error(1, "$ctrl.$method param error:$chret"); break;
	case RT_ERR: request_error(1, "$ctrl.$method return 0"); break;
	case RT_NONE: break;
	case RT_TPL:
		if($obj->page['size'] != 0)
		{
			$obj->assign('key_search', $obj->search);
			$obj->assign('curPage', $obj->page['cur']);
			$obj->assign('pageSize', $obj->page['size']);
			$obj->assign("totalCnt", $obj->page['cnt']);
			$obj->assign("pageCnt", $obj->page['pageCnt']);
		}
		$obj->assign('cur_date',  date("Y-m-d"));
		$obj->assign('cur_time',  date("Y-m-d H:i:s"));
		$obj->display($ctrlbase . "_" . $method . '.tpl');
		$obj->user->Active();		//有操作，延迟登录失效
		break;
	case RT_PHP: require_once($obj->template_dir[0] . $ctrlbase . "_" . $method . '.php'); break;
	case RT_MSG: $obj->display('global_message.tpl'); break;
	case RT_ATTACK: full_log(); break;
	default:
		echo json_encode($ret);
	}
	return true;
}

function check_param($obj, $method)
{
	$vars = array(
		"GET" => $_GET,
		"POST" => $_POST,
		"REQUEST" => $_REQUEST,
		"SESSION" => $_SESSION,
		"COOKIE" => $_COOKIE,
		"FILES" => $_FILES,
	);
	foreach($obj->paramCheck[$method] as $k => $p)
	{
		$cur_var = $vars[$p[0]];
		if(!array_key_exists($k, $cur_var))
		{
			if($p[1] === "must") //必须参数
				return $k;
			else
			{
				deal_param($obj, $p, $k, $p[1], false); //设置默认
				continue;
			}
		}
		$v = $cur_var[$k];
		if($p[1] === $v)	//如果传值与默认值相同，忽略
		{
			deal_param($obj, $p, $k, $v, false);
			continue;
		}
		if($p[2] != "")
		{
			$v = $p[2]($v);
			if($v === false)
				return $k;
			//start 防攻击代码, 方法一和方法二只需要一个即可
			if(ATTACK_DEF != 0 && $p[2] == "trim")
			{
				if(ATTACK_DEF == 1)
				{
					//方法一
					$v = preg_replace('/[\'\"<>]/', '', $v);	//暴力防攻击，破坏一切攻击
				}
				else
				{
					//方法二
					$v = preg_replace('/[\'\"]/', '', $v);	//暴力防sql入侵
					$v = htmlspecialchars($v);				//暴力防xss攻击
				}
			}
			//end
		}
		else
			$v = $cur_var[$k];
		switch($p[3])
		{
		case "tel": if(preg_match(TEL_REG, $v) == 0) return $k.' should tel'; break;
		case "mobile": if(preg_match(MOBILE_REG, $v) == 0) return $k.' should mobile'; break;
		case "email": if(preg_match(EMAIL_REG, $v) == 0) return $k.' should email'; break;
		case "notempty": if($v == "") return $k.' should notempty'; break;
		case "notnull": if(is_null($v)) return $k.' should notnull'; break;
		case "notzero": if($v == 0) return $k.' should notzero'; break;
		case "positive": if($v <= 0) return $k.' should positive'; break;
		case "notnegative": if($v < 0) return $k.' should notnegative'; break;
		case "bool": if($v < 0 || $v > 1) return $k.' should bool'; break;
		case 'date': if(preg_match('/^\d{4}-(0[1-9]|1[012])-[0-3]\d$/', $v) == 0) return $k.' should date'; break;
		case 'datetime': if(preg_match('/^\d{4}-(0[1-9]|1[012])-[0-3]\d [012]\d(:[0-5]\d){2}$/', $v) == 0) return $k.' should datetime'; break;
		case 'timeslot': if(preg_match('/^[012]\d:[03]0-[012]\d:[03]0$/', $v) == 0) return $k.' should timeslot'; break;
		case '': break;
		default:
			SysDie('T_CODE', 'E_UND', $p[3]);
		}
		deal_param($obj, $p, $k, $v, true);
	}
	//var_dump($obj->params);
	return "0";
}

/*
 * 处理一些特殊参数
 */
function deal_param(&$obj, &$p, &$k, &$v, $set)
{
	$obj->params[$k] = $v;
	if($k == 'page')
		$obj->page['cur'] = $v;
	else if($k == 'pageSize')
		$obj->page['size'] = $v;
	else if($set && isset($p[4]))
	{
		switch($p[4])
		{
		case 's':		//搜索处理
			$obj->search[$k] = $v;
			break;
		}
	}
}

/*
 * 根据系统法定的参数获得where
 */
function get_where($obj, &$search)
{
	$where = '';
	foreach($search as $k =>$v)
	{
		if($k == 'key')
		{
			if(array_key_exists('keyword', $search))
			{
				if(array_key_exists($v, $obj->key_cover))		//转义
					$v2 = $obj->key_cover[$v];
				else
					$v2 = '`'.$v.'`';
				if(array_key_exists($v, $obj->key_eq))			//精确搜索
					$where .= " and $v2 = '" . $search['keyword']. "'";
				else
					$where .= " and $v2 like '%" . $search['keyword']. "%'";
			}
		}
		else if($k != 'keyword')
		{
			if(array_key_exists($k, $obj->key_cover))		//转义
				$where .= ' and ' . $obj->key_cover[$k] . " '$v'";
			else
				$where .= " and `$k` = '$v'";
		}
	}
	if($where == '')
		return '1';
	else
		return '1' . $where;
}

function SaveExcel($fileName, $headArr, $data, $type)
{
	require_once('../PHPExcel/PHPExcel.php');
    //创建新的PHPExcel对象
    $objPHPExcel = new PHPExcel();
    $objProps = $objPHPExcel->getProperties();
     
    //设置表头
    $key = ord("A");
    foreach($headArr as $v){
        $colum = chr($key);
        $objPHPExcel->setActiveSheetIndex(0) ->setCellValue($colum.'1', $v);
        $key += 1;
    }
	$objPHPExcel->getActiveSheet()->getColumnDimension('A')->setAutoSize(true);
	$objPHPExcel->getActiveSheet()->getColumnDimension('B')->setAutoSize(true);
	$objPHPExcel->getActiveSheet()->getColumnDimension('C')->setAutoSize(true);
     
    $column = 2;
    $objActSheet = $objPHPExcel->getActiveSheet();
    foreach($data as $key => $rows){ //行写入
        $span = ord("A");
        foreach($rows as $keyName=>$value){// 列写入
            $j = chr($span);
            $objActSheet->setCellValue($j.$column, $value);
            $span++;
        }
        $column++;
    }
 
    $fileName = iconv("utf-8", "gb2312", $fileName);
    //重命名表
    $objPHPExcel->getActiveSheet()->setTitle('Simple');
    //设置活动单指数到第一个表,所以Excel打开这是第一个表
    $objPHPExcel->setActiveSheetIndex(0);
	$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
	if($type != 'save')
	{
		//将输出重定向到一个客户端web浏览器(Excel2007)
		ob_clean();
		header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
		header("Content-Disposition: attachment; filename=\"$fileName\"");
		header('Cache-Control: max-age=0');
		//flush();
		return $objWriter->save('php://output'); //文件通过浏览器下载
	}
	else
		return $objWriter->save($fileName); //脚本方式运行，保存在当前目录
}

function jump_to($url, $notice='')
{
	global $ajax;	
	if($ajax)
	{
		if($notice == '')
			$notice = '访问无效';
		echo "$notice\n请刷新页面或者访问“${url}”";
		exit();
	}
	$msg = <<<EOF
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<script language='javascript' type='text/javascript'>
EOF;
	if($notice != '')
		$msg .= "\nalert('$notice');";
	if(JUMP_WAIT)
		$msg .= "\nalert('jump to $url');";
	$msg .= "\nwindow.location.href=\"$url\"\n</script>";
	echo $msg;
	exit();
}

function json_decode_array($str)
{
	return json_decode($str, 1);
}

function replace_star($str)
{
	switch(strlen($str))
	{
	case 1: return $str . "*";
	case 2: return substr($str, 0, 1) . "*" . substr($str, 1, 1);
	default:
		return preg_replace("/(?<=.{2}).+?(?=.{2})/", "*", $str);
	}
}

function RmFile($file, &$msg)
{
	if(!is_file($file))
	{
		$msg = "文件不存在";
		return -1;
	}
	if(unlink($file))
		return 0;
	else
	{
		$msg = "删除文件失败";
		return -2;
	}
}

function SafeDownFile($file, &$msg)
{
	//必须调用之前确认权限正常
	if (!file_exists($file)) 
	{
		$msg = "文件不存在";
		return -1;
	}
	header('Content-Description: File Transfer');    
	header('Content-Type: application/octet-stream');    
	header('Content-Disposition: attachment; filename='.basename($file));    
	header('Content-Transfer-Encoding: binary');    
	header('Expires: 0');    
	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');    
	header('Pragma: public');    
	header('Content-Length: ' . filesize($file));    
	ob_clean();   //重要的就是这个函数的调用， 清空但不关闭输出缓存， 否则下载的文件头两个字符会是0a 
	flush();    
	if(!readfile($file))   // 输出文件内容 
	{
		$msg = "打开文件失败";
		return -2;
	}
	return 0;
}

//校验图片验证码
function CheckImgAuthcode($val)
{
	if(array_key_exists("authcode", $_SESSION))
	{
		$code = $_SESSION['authcode'];
		unset($_SESSION['authcode']);
		return intval($val) == $code;
	}
	return false;
}

function SendMail($addrTo, $title, $content)
{
	global $mail_conf;
	require("include/class.phpmailer.php");
	$mail = new PHPMailer();

	$mail->IsSMTP();
	$mail->SMTPAuth = true;
	$mail->Host = $mail_conf['host'];
	$mail->Username = $mail_conf['username'];
	$mail->From = $mail_conf['from'];
	$mail->Password = $mail_conf['password'];
	$mail->CharSet = "utf-8";
	$mail->Encoding = "base64";

	$mail->FromName = "梵地蛋糕";
	$mail->AddAddress($addrTo);

	$mail->WordWrap = 50;
	//$mail->AddAttachment("/tmp/image.jpg", "new.jpg");
	$mail->IsHTML(true);

	$mail->Subject = "梵地蛋糕提示-" . $title;
	$mail->Body    =  $content;
	$mail->AltBody = "html不被支持，请联系客服";

	return $mail->Send();
}

//加密
function RsaEncrypt($data, &$msg)
{
	global $conf;
	$key = file_get_contents($conf['rsa_pub']);
	if(!$key)
	{
		$msg = "密钥打开失败";
		return false;
	}
	$pubKey = openssl_pkey_get_public($key);
	if(!$pubKey)
	{
		$msg = "密钥错误";
		return false;
	}
	$out = "";
	if(!openssl_public_encrypt($data, $out, $pubKey)) //, OPENSSL_NO_PADDING))
	{
		$msg = "加密错误";
		return false;
	}
	return $out;
}

//解密
function RsaDecrypt($data, &$msg)
{
	global $conf;
	$key = file_get_contents($conf['rsa_pri']);
	if(!$key)
	{
		$msg = "密钥打开失败";
		return false;
	}
	$priKey = openssl_pkey_get_private($key);
	if(!$priKey)
	{
		$msg = "密钥错误";
		return false;
	}
	$out = "";
	if(!openssl_private_decrypt($data, $out, $priKey))
	{
		$msg = "解密错误";
		return false;
	}
	return $out;
}

//发送短信
function SendMobileMsg(&$retmsg, $mobiles, $content)
{
	//if(strlen($content) >= 45)
	//	SysDie('T_MSG', 'E_FAIL', "短信太长：".$content);
	global $mobile_allowed;
	foreach($mobiles as $item)
	{
		if(!in_array($item, $mobile_allowed))
			SysDie('T_MSG', 'E_FAIL', "测试期间不被允许：".$item);
	}
	global $zucp_conf;
	$msg_conf = $zucp_conf;
	$content .= "\n".date('H:i:s')."【梵地蛋糕】";
	//test
	$content = strlen($content).$content;
	$content = iconv("UTF-8","GB2312",$content);
	$data = array(
		'sn' => $msg_conf['sn'],
		'pwd' => $msg_conf['pwd'],
		'mobile' => implode(',', $mobiles),
		'content' => $content,
	);
	//ksort($data);
	$sd = http_build_query($data, '', '&');
	//var_dump(urldecode($sd));
	$context = array(
		'http' => array(
			'method' => 'POST',
			'header' => 'Content-type: application/x-www-form-urlencoded',
			'content' => $sd),
	);
	$stream_context = stream_context_create($context);
	//$url_in = 'http://sdk.entinfo.cn:8060/z_mdsmssend.aspx';
	$url_in = 'http://sdk2.zucp.net:8060/z_send.aspx';
	$ret = file_get_contents($url_in, false, $stream_context);
	if(!$data)
		SysDie('T_MSG', 'E_NET', '');
	$ret_msgs = array(
		'0' => '没有需要取得的数据',
		'1' => '发送成功',
		'-4' => '余额不足，扩展码错误',
		'-3' => '序列号密码不正确',
		'-2' => '参数错误',
		'-1' => '发送失败',
	);
	if($ret == 1)
	{
		$retmsg = $ret_msgs[$ret];
		return true;
	}
	else
	{
		if(array_key_exists($ret, $ret_msgs))
			$retmsg = $ret_msgs[$ret];
		else
			$retmsg = "未定义返回值".$ret;
		SysDie('T_MSG', 'E_FAIL', $retmsg);
	}
	return false;
}

/*
function SendMobileMsg(&$retmsg, $mobiles, $content)
{
	global $qf106_conf;
	$msg_conf = $qf106_conf;
	$content .= "\n".date('Y-m-d H:i:s')."\n[梵地蛋糕]";
	$data = array(
		'action' => 'send',
		'userid' => $msg_conf['userid'],
		'account' => $msg_conf['account'],
		'password' => $msg_conf['password'],
		'mobile' => implode(',', $mobiles),
		'content' => $content,
	);
	ksort($data);
	$sd = http_build_query($data);
	$context = array(
		'http' => array(
			'method' => 'POST',
			'header' => 'Content-type: application/x-www-form-urlencoded',
			'content' => $sd),
	);
	$stream_context = stream_context_create($context);
	$data = file_get_contents("http://www.qf106.com/sms.aspx", false, $stream_context);
	if(!$data)
		SysDie('T_MSG', 'E_NET', '');
	$obj = simplexml_load_string($data);
	if(!$obj)
		SysDie('T_MSG', 'E_FORMAT', '');
	$retmsg = $obj->message;
	if($obj->returnstatus == 'Success')
		return true;
	else
		SysDie('T_MSG', 'E_FAIL', $obj->message);
	return false;
}
 */

/*
 * 根据时间日期获取时间段格式
 */
function SlotFormt($type, $datetime)
{
	if($datetime == '')
		return '';
	//2013-10-29 11:00-00:00 <= 2013-10-29 11:33 <=2013-10-29 11:99-99:99
	$ret = "";
	if($type == 'beg')
		$ret = substr($datetime, 0, 14). "00-00:00";
	else
		$ret = substr($datetime, 0, 14). "99-99:99";
	return $ret;
}

/*
 * 生成序列号
 */

function CreateNo($pre, $len)
{
	$pre = strtoupper($pre);
	$key = $pre . time(0) . rand();
	$msg;
	$val= RsaEncrypt($key, $msg);
	if(!$val)
		return false;
	$val = strtoupper(base64_encode($val));
	$val = preg_replace('/[\+\/]/', '0', $val);
	$arr = str_split($val, $len);
	$cnt = floor(count($arr) / 2);
	$rst = array();
	for($i = 0; $i < $cnt; $i++)
	{
		$no = $pre.'-'.$arr[$i*2].'-'.$arr[$i*2+1];
		$no .= '-'.strtoupper(substr(md5($no), 0, $len));
		$rst[] = $no;
	}
	return $rst;
}

/*
 * 校验序列号格式
 */

function CheckNo($no)
{
	$len = (strlen($no)-3)/4;
	$pre = substr($no, 0, $len*3+2);
	$mark = substr($no, $len*3+3, $len);
	$nmark = strtoupper(substr(md5($pre), 0, $len));
	return $mark === $nmark;
}

/*
 * 显示支付宝界面
 */

function DisplayZFB($id, $amount, $note, $showurl)
{
	global $g_ZFB_conf;
   if(empty($g_ZFB_conf['account']))
	   SysDie('T_ZFB', 'E_UCONF', '');
	require_once('../zfb/alipayapi.php');
    echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
	ZFB_Fun(MakeTradeId($id), $amount, '梵地蛋糕-'.$note, $showurl);
}

/*
 * 根据ID生成交易ID
 */

function MakeTradeId($id)
{
	return 'OL'.str_pad($id,8,'0',STR_PAD_LEFT);
}

/*
 * 根据交易ID生成数据ID
 */

function GetDataId($tradeid)
{
	return intval(substr($tradeid, 2));
}

/*
 * 自动限制时间
 */
function TimeLimit(&$conObj, $key, $second)
{
	unset($_SESSION['time_limit']);
	if(array_key_exists('time_limit', $_SESSION))
		$obj = $_SESSION['time_limit'];
	else
	{
		$obj = array();
		$_SESSION['time_limit'] = $obj;
	}
	$now = time(0);
	if(array_key_exists($key, $obj))
		$data = $obj[$key];
	else
		$data = array('last' => 0, 'rt_cnt' => 0);
	$left = $data['last'] + $second - $now;
	if($left <= 0)	//达到限制
	{
		$data['last'] = $now;
		$data['rt_cnt'] = 0;
		$ret = false;
	}
	else
	{
		$data['rt_cnt']++;
		//过于频繁处理一下
		$conObj->assign('msg', "操作频繁, 请${left}秒之后重试");
		$ret = true;
	}
	$_SESSION['time_limit'][$key] = $data;
	return $ret;
}

function RandStr($length = 8 )
{
	// 密码字符集，可任意添加你需要的字符
	$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; //!@#$%^&*()-_ {}<>~`+=,.;:/?|';
	$s_len = strlen($chars) - 1;
	$password = '';
	for ( $i = 0; $i < $length; $i++ )
		$password .= $chars[ mt_rand(0, $s_len) ];
	return $password;
}

/*
 * 随机设置参数，进行测试
 */
function RandParam()
{
	foreach($_GET as $k => $item)
		$_GET[$k] = RandVal($item);
	foreach($_POST as $k => $item)
		$_POST[$k] = RandVal($item);
}

function RandVal($item)
{
	$nitem = $item;
	$r = rand();
	$c = '';
	switch($r % 5 == 0)
	{
	case 0: $c = 'a'; break;
	case 1: $c = '1'; break;
	case 2: $c = '0'; break;
	case 3: $c = ' '; break;
	case 4: $c = '\0'; break;
	}
	if($r % 5 == 0)		//
	{
		$len = strlen($item);
		if($len == 0)
		{
			$item = "123test";
			$len = 6;
		}
		$pos = rand(0, $len - 1);
		$nitem = substr_replace($item, $c, $pos, 1);
	}
	return $nitem;
}

